#
#   Bacon Vs Eggs
#   Version ?
#
#   Daniel Sabo, Nathan Adams, Bret Deasy
#
#
#   Artwork by:
#   Nathan Adams
#   "Game Design Title" design by Daniel Cook (Lostgarden.com)
#

import sys
sys.path.append("C:\\Panda3D-1.7.2\\")
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.gui.DirectGui import *
from pandac.PandaModules import TextNode
from pandac.PandaModules import Point2,Point3,Vec3,Vec4
from direct.stdpy.threading import Timer
from direct.task.Task import Task
from pandac.PandaModules import *
from panda3d.core import NodePath
from panda3d import physics
import time
from math import cos,sin,radians
import cPickle
from pig import Pig
from nest import Nest
from cannon import Cannon
from block import Block
from pandac.PandaModules import OdeWorld
from Level import Level
SCREEN_X = 20       #Screen goes from -20 to 20 on X
SCREEN_Y = 15       #Screen goes from -15 to 15 on Y

class Stage(DirectObject):
    def __init__(self, m):
        self.disableMouse2Cam()
        self.pigs = []
        self.grassarr = []
        self.m = m
        
        self.grasstexture = loader.loadTexture("../media/Grass_Block.png")
        self.cannontexture = loader.loadTexture("../media/cannonBase.png")
        self.cannonheadtexture = loader.loadTexture("../media/cannonhead.png")
        self.tree1texture = loader.loadTexture("../media/tree1.png")
        #self.nest1texture = loader.loadTexture("../media/nest1.png")
        self.bgtexture = loader.loadTexture("../media/sky.jpg")
       # self.pigtexture = loader.loadTexture("../media/pig.png")

        # 9/29/2011 Using ODE now
        #base.physics = PhysicsCollisionHandler()
        #base.physics.addInPattern("%fn-in-%in")
        #base.physics.addOutPattern("%fn-out-%in")
        #base.enableParticles()

        # 9/29/2011 Using ODE now
        #self.node = NodePath("PhysicsNode") #Create Physics Node
        #self.node.reparentTo(render) #Update node each frame
        #self.gravity = physics.ForceNode('forces') #creates gravity force
        #self.gravityNode = render.attachNewNode(self.gravity) #attaches gravity to node list
        #self.gravityForce = physics.LinearVectorForce(0,0,-9.81) #defines gravity
        #self.gravity.addForce(self.gravityForce) #adds definition to force
        #base.physicsMgr.addLinearForce(self.gravityForce) #adds gravity to physics engine
        
        self.setupScene()

    def loop(self,task):
        delta = task.time - task.last
        task.last = task.time
        
        for pig in self.pigs: self.updatePos(pig.pig,delta)
        return Task.cont
    
    def launchpig(self):
        
        piggy = Pig()
        #piggy.setPhysics()
        #piggy.setCollision(self.collTrav)
        #self.setVelocity(piggy.pig,Vec3(10*cos(-radians(self.cannonobj.R)),0,10*sin(-radians(self.cannonobj.R))))
        self.pigs.append(piggy)
        #print self.cannonheadobj.getR()

    def updatePos(self, obj, dt):
        vel = self.getVelocity(obj)
        newPos = obj.getPos() + (vel*dt)

    #Check if the object is out of bounds. If so, wrap it
        radius = .5 * obj.getScale().getX()
        if newPos.getX() - radius > SCREEN_X: newPos.setX(-SCREEN_X)
        elif newPos.getX() + radius < -SCREEN_X: newPos.setX(SCREEN_X)
        if newPos.getZ() - radius > SCREEN_Y: newPos.setZ(-SCREEN_Y)
        elif newPos.getZ() + radius < -SCREEN_Y: newPos.setZ(SCREEN_Y)
        
        obj.setPos(newPos)

    def setVelocity(self, obj, val):
        list = [val[0], val[1], val[2]]
        obj.setTag("velocity", cPickle.dumps(list))

    def getVelocity(self, obj):
        list = cPickle.loads(obj.getTag("velocity"))
        return Vec3(list[0], list[1], list[2])
    
    def setupScene(self):
        self.cannonobj = Cannon()
        self.pigflytime = int(time.time()) - 10
        self.accept("mouse1", self._button, [1])
        self.accept("mouse2", self._button, [2])
        self.accept("mouse3", self._button, [3])
        self.accept("escape", self.back)
        self.accept("space",  self.fire)
        self.accept("arrow_up-repeat", self.cannonobj.moveCannon, [0]) # 1 = move up
        self.accept("arrow_down-repeat", self.cannonobj.moveCannon, [1]) # 0 = move down
        self.accept("arrow_up", self.cannonobj.moveCannon, [0]) # 1 = move up
        self.accept("arrow_down", self.cannonobj.moveCannon, [1]) # 0 = move down
        self.accept("PigSphere-in-nestSphere", self.score)
        #self.accept("PigSphere-in-floor", self.onCollisionStart)
        #self.accept("PigSphere-out-floor", self.onCollisionEnd)
        self.accept("space", self.firepig)
        self.accept("x", self.toggle_wire)
        self.accept("d", self.toggle_debug)
        self.loadgrass()
        
    def toggle_debug(self):
        if self.cameramousemove:
            self.disableMouse2Cam()
        else:
            self.enableMouse2Cam()
        messenger.toggleVerbose()
    
    def score(self,entry):
        print "SCORE"
    
    def firepig(self):
      #  if (int(time.time()) - self.pigflytime) >= 5:            
       #     self.pigflytime = int(time.time())
        self.launchpig()
    

            
    def back(self):
        for g in self.grassarr:
            g.hide()
        self.cannonobj.hide()
        self.ignoreAll()
        self.cannonheadobj.hide()
        self.m.showbuttons()
        self.treeobj.hide()
        #self.nestobj.hide()
    
    def loadobject(self, textureobj):
        obj = loader.loadModel("../media/plane")
        obj.reparentTo(camera)
        #obj.setBin("unsorted", 0)
        obj.setBin("unsorted", 0)           #This tells Panda not to worry about the
                                          #order this is drawn in. (it prevents an
                                          #effect known as z-fighting)
        obj.setDepthTest(False)             #Tells panda not to check if something
                                          #has already drawn in front of it
                                          #(Everything in this game is at the same
                                          #depth anyway)
        obj.setTransparency(1)
        obj.setTexture(textureobj, 1)
        return obj
        
    def loadgrass(self):

        xcord = -3.1
        ycord = -2.2
        self.bg = self.loadobject(self.bgtexture)
        self.bg.setPos(Point3(0,200,0))
        self.bg.setScale(150)
        if not self.grassarr:
            for i in range(1, 9):
                obj = self.loadobject(self.grasstexture)
                pos = Point2(xcord,-2.2) # left coord = -3.1, -2.2
                xcord += 1.001
                depth = 10
                obj.setPos(Point3(pos.getX(), depth, pos.getY())) #Set initial position
                self.grassarr.append(obj)

            self.collTrav = CollisionTraverser()
            base.cTrav = self.collTrav
            self.collTrav.showCollisions(render)
            
            #self.cannonheadobj = self.loadobject(self.cannonheadtexture)
            #pos = Point2(-3.0,-1.7)
            #self.cannonheadobj.setPos(Point3(pos.getX(), 10, pos.getY()))
            
            #self.cannonobj = self.loadobject(self.cannontexture)
            #pos = Point2(-3.15,-1.9)
            #self.cannonobj.setPos(Point3(pos.getX(), 10, pos.getY()))
            #self.cannonobj.setH(50)

            self.treeobj = self.loadobject(self.tree1texture)
            pos = Point2(1, -0.5)
            self.treeobj.setPos(Point3(pos.getX(),10, pos.getY()))
            self.treeobj.setScale(4,1,4)

            # self.nestobj = self.loadobject(self.nest1texture)
            #pos = Point2(0,0)
            #self.nestobj.setPos(Point3(pos.getX(), 10, pos.getY()))
            self.nestobj = Nest()
            self.nestobj.setPhysics()
            self.nestobj.setCollision(self.collTrav)

          #  self.thrustNode = ForceNode("thrust")
          #  self.phys.attachNewNode(thrustNode)
          #  self.thrustForce = LinearVectorForce(0,0,400)
          #  self.thrustForce.setMassDependent(1)
         #   thrustNode.addForce(self.thrustForce)

            self.floor = render.attachNewNode(CollisionNode("floor"))
            self.floor.node().addSolid(CollisionPlane(Plane(Vec3(0,0,1),Point3(0,0,-2.5))))
            self.floor.show()
            
            self.gameTask = taskMgr.add(self.loop,"loop")
            self.gameTask.last = 0
            
            # Setting up collision

            #self.collisionHandler = CollisionHandlerEvent()
            #self.pusher = PhysicsColliderHandler()
            
            # Add object for nest
            #self.nestsphere = CollisionSphere(0,0,0,1)
            #self.nestcolnode = CollisionNode('nestsphere')
            #self.nestcolnode.addSolid(self.nestsphere)
            
            #nestcollider = self.nestobj.attachNewNode(self.nestcolnode)
            #nestcollider.node().addSolid(self.nestsphere)
            #self.collTrav.addCollider(nestcollider, self.collisionHandler)
            #nestcollider.show()
            
            #self.collisionHandler.addInPattern('%fn-into-%in')
            #self.collisionHandler.addOutPattern('%fn-out-%in')  
            
            self.blocks = []
            for i in range(0,10):
                self.blocks.append(Block())
                self.blocks[i].setXY(None, i+-1)
                self.blocks[i].setPhysics()
                self.blocks[i].setCollision(self.collTrav)
        else:
            for g in self.grassarr:
                g.show()
            self.cannonobj.show()
            self.cannonheadobj.show() 
            self.treeobj.show()
            self.nestobj.show()
    def disableMouse2Cam(self): 
        self.cameramousemove = False
        base.mouseInterface.detachNode() 

    def enableMouse2Cam(self):
        self.cameramousemove = True
        base.mouseInterface.reparentTo(base.mouseWatcher)
    def fire(self):
        pass
        
    def _button(self, bnum):
        print base.mouseWatcherNode.getMouseY()
        pass

    def toggle_wire(self):
        base.toggleWireframe()
        base.toggleTexture()

    #def onCollisionStart(self, entry):
    #    base.physicsMgr.addlinearForce(self.thrustForce)

    #def onCollisionEnd(self, entry):
    #   base.physicsMgr.removeLinearForce(self.thrustForce)
        

class Menu(DirectObject):
    buttons = []
    b = None
    b2 = None
    s = None
    start_maps = None
    exit_maps = None
    def __init__(self):
        self.start_maps = loader.loadModel('../media/start_button_maps.egg')
        self.exit_maps = loader.loadModel('../media/exit_button_maps.egg')
        #self.accept("escape",  self.exit)

        # Add button
        #b = DirectButton()
        self.showbuttons()
        
        
    def showbuttons(self):
        if not self.buttons:
            b = DirectButton(scale=.4, command=self.game, geom = (self.start_maps.find('**/start'),
                             self.start_maps.find('**/start'),
                             self.start_maps.find('**/start'),
                             self.start_maps.find('**/start')))
                             
            b2 = DirectButton(scale=.4, command=self.exit, geom = (self.exit_maps.find('**/exit'),
                     self.exit_maps.find('**/exit'),
                     self.exit_maps.find('**/exit'),
                     self.exit_maps.find('**/exit')))
            #for i in dir(b):
            #    print i
            b.setPos(0,0,.6)
            b2.setPos(0,0,-.1)
            
            self.buttons.append(b)
            self.buttons.append(b2)
        else:
            for b in self.buttons:
                b.show()
        self.accept("escape",  self.exit)

    def game(self):
        for b in self.buttons:
            b.hide()
        self.ignoreAll()
        if self.s:
            self.s.setupScene()
        else:
            self.s = Stage(self)
        # print "back!"
        #self.accept("escape",  self.exit)
        #self.showbuttons()
    
    def exit(self):
        sys.exit(0)

        
#m = Menu()
#run()
lvl1 = Level("../media/lvl1.bve")
